home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2001 December / pcwk12201b.iso / Wersje pelne i specjalne / Winamp 2.77 i 3.0beta / wasabi-sdk_beta1.exe / studio / common / bitmap.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  29KB  |  1,122 lines

  1. /*
  2.  
  3.   Nullsoft WASABI Source File License
  4.  
  5.   Copyright 1999-2001 Nullsoft, Inc.
  6.  
  7.     This software is provided 'as-is', without any express or implied
  8.     warranty.  In no event will the authors be held liable for any damages
  9.     arising from the use of this software.
  10.  
  11.     Permission is granted to anyone to use this software for any purpose,
  12.     including commercial applications, and to alter it and redistribute it
  13.     freely, subject to the following restrictions:
  14.  
  15.     1. The origin of this software must not be misrepresented; you must not
  16.        claim that you wrote the original software. If you use this software
  17.        in a product, an acknowledgment in the product documentation would be
  18.        appreciated but is not required.
  19.     2. Altered source versions must be plainly marked as such, and must not be
  20.        misrepresented as being the original software.
  21.     3. This notice may not be removed or altered from any source distribution.
  22.  
  23.  
  24.   Brennan Underwood
  25.   brennan@nullsoft.com
  26.  
  27. */
  28.  
  29. #include <windows.h>
  30.  
  31.  
  32. //#define NO_SIMPLEFASTMODE
  33.  
  34. #include "blending.h"
  35.  
  36. #include "bitmap.h"
  37. #include "../studio/api.h"
  38. #include "std.h"
  39. #include "canvas.h"
  40.  
  41.  
  42. #define ERRORBMP "studio/error.png"
  43.  
  44. // do not define NO_MMX in this file. :)
  45.  
  46. #ifndef NO_MMX
  47. static unsigned int const SkinBitmap_mmx_revn2[2]={0x01000100,0x01000100};
  48. static unsigned int const SkinBitmap_mmx_zero[2];
  49. static unsigned int const SkinBitmap_mmx_one[2]={1,0};
  50. #define HAS_MMX Blenders::MMX_AVAILABLE()
  51. #else
  52. #define HAS_MMX 0
  53. #endif
  54.  
  55.  
  56. SkinBitmap::SkinBitmap(HINSTANCE hInstance, int id) {
  57.   subimage_w=-1;
  58.   subimage_h=-1;
  59.   x_offset=-1;
  60.   y_offset=-1;
  61.   fullimage_w=fullimage_h=0;
  62.   has_alpha = 0;
  63.   ASSERT(hInstance != NULL);
  64.   ownbits=1;
  65.   bits=api->imgldr_makeBmp(hInstance, id,&has_alpha,&fullimage_w,&fullimage_h);
  66. }
  67.  
  68. void SkinBitmap::bmpToBits(HBITMAP hbmp, HDC defaultDC)
  69. {
  70.   if (hbmp && !bits) 
  71.   {
  72.     BITMAPINFO srcbmi={0,};
  73.     HDC hMemDC, hMemDC2;
  74.     HBITMAP hprev,hprev2;
  75.     HBITMAP hsrcdib;
  76.     void *srcdib;
  77.     BITMAP bm;
  78.     int r = GetObject(hbmp, sizeof(BITMAP), &bm);
  79.     ASSERT(r != 0);
  80.  
  81.     fullimage_w=bm.bmWidth;
  82.     fullimage_h=ABS(bm.bmHeight);
  83.  
  84.     int bmw=getWidth();
  85.     int bmh=getHeight();
  86.     int xo=getX();
  87.     int yo=getY();
  88.  
  89.     srcbmi.bmiHeader.biSize=sizeof(srcbmi.bmiHeader);
  90.     srcbmi.bmiHeader.biWidth=bmw;
  91.     srcbmi.bmiHeader.biHeight=-bmh;
  92.     srcbmi.bmiHeader.biPlanes=1;
  93.     srcbmi.bmiHeader.biBitCount=32;
  94.     srcbmi.bmiHeader.biCompression=BI_RGB;
  95.     hMemDC = CreateCompatibleDC(NULL);
  96.     hsrcdib=CreateDIBSection(hMemDC,&srcbmi,DIB_RGB_COLORS,&srcdib,NULL,0);
  97.     ASSERTPR(hsrcdib != 0, "CreateDIBSection() failed #6");
  98.     if (defaultDC) 
  99.       hMemDC2 = defaultDC;
  100.     else {
  101.       hMemDC2 = CreateCompatibleDC(NULL);
  102.       hprev2 = (HBITMAP) SelectObject(hMemDC2, hbmp);
  103.     }
  104.     hprev = (HBITMAP) SelectObject(hMemDC, hsrcdib);
  105.     BitBlt(hMemDC,0,0,bmw,bmh,hMemDC2,xo,yo,SRCCOPY);
  106.     SelectObject(hMemDC, hprev);
  107.     if (!defaultDC) {
  108.       SelectObject(hMemDC2, hprev2);
  109.       DeleteDC(hMemDC2);
  110.     }
  111.     DeleteDC(hMemDC);
  112.     bits=(int*)MALLOC(bmw*bmh*4);
  113.     if (getHeight()+getY() > bm.bmHeight || getWidth()+getX() > bm.bmWidth) {
  114.       char txt[128];
  115.       SPRINTF(txt, "Subbitmap coordinates outside master bitmap [%d,%d,%d,%d in 0,0,%d,%d]", getX(), getY(), getWidth(), getHeight(), bm.bmWidth, bm.bmHeight);
  116.       ASSERTPR(0, txt);
  117.     }
  118.     MEMCPY(bits,srcdib,bmw*bmh*sizeof(int));
  119.     DeleteObject(hsrcdib);
  120.     x_offset=-1;
  121.     y_offset=-1;
  122.     subimage_w=-1;
  123.     subimage_h=-1;
  124.     fullimage_w=bmw;
  125.     fullimage_h=bmh;
  126.   }
  127. }
  128.  
  129. SkinBitmap::SkinBitmap(const char *filename, int _cached) {
  130.   ASSERT(filename != NULL);
  131.  
  132.   BOOL isldd = TRUE;
  133.   x_offset = -1;
  134.   y_offset = -1;
  135.   subimage_w = -1;
  136.   subimage_h = -1;
  137.   fullimage_w=fullimage_h=0;
  138.   ownbits=1;
  139.   bits = api->imgldr_requestSkinBitmap(filename, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
  140.   if (bits == NULL) bits = api->imgldr_makeBmp(ERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
  141.  
  142.   ASSERTPR(bits != NULL, filename);
  143. }
  144.  
  145. SkinBitmap::SkinBitmap(HBITMAP bitmap) {
  146.   ASSERT(bitmap != NULL);
  147.   subimage_w=-1;
  148.   subimage_h=-1;
  149.   x_offset=-1;
  150.   y_offset=-1;
  151.   fullimage_w=fullimage_h=0;
  152.   has_alpha = 0;
  153.   ownbits=1;
  154.   bits = NULL;
  155.   bmpToBits(bitmap,NULL);
  156. }
  157.  
  158. SkinBitmap::SkinBitmap(HBITMAP bitmap, HDC dc, int _has_alpha, void *_bits) {
  159.   subimage_w=-1;
  160.   subimage_h=-1;
  161.   x_offset=-1;
  162.   y_offset=-1;
  163.   fullimage_w=fullimage_h=0;
  164.   ASSERT(bitmap != NULL);
  165.   has_alpha = _has_alpha;
  166.   bits = (int*)_bits;
  167.   if (!_bits) 
  168.   {
  169.     ownbits=1;
  170.     bmpToBits(bitmap,dc);
  171.   }
  172.   else
  173.   {
  174.     BITMAP bm;
  175.     ownbits=0;
  176.     int r = GetObject(bitmap, sizeof(BITMAP), &bm);
  177.     ASSERT(r != 0);
  178.     fullimage_w=bm.bmWidth;
  179.     fullimage_h=ABS(bm.bmHeight);
  180.   }
  181. }
  182.  
  183.  
  184. SkinBitmap::SkinBitmap(int w, int h, DWORD bgcolor) {
  185.   subimage_w=-1;
  186.   subimage_h=-1;
  187.   x_offset=-1;
  188.   y_offset=-1;
  189.   fullimage_w=w;
  190.   fullimage_h=h;
  191.  
  192.   bits=(int*)MALLOC(w*h*sizeof(int));
  193.  
  194.   DWORD *dw = (DWORD *)bits;
  195.   int l=w*h;
  196.   while (l--) *dw++=bgcolor;
  197.   has_alpha = TRUE;
  198.   ownbits=2; // 2 specifies should be FREE()'d
  199. }
  200.  
  201. SkinBitmap::~SkinBitmap() {
  202.   if (bits)
  203.   {
  204.     if (ownbits==2) FREE(bits);
  205.     else if (ownbits) api->imgldr_releaseSkinBitmap(bits);
  206.   }
  207.   bits=NULL;
  208. }
  209.  
  210. void SkinBitmap::blit(CanvasBase *canvas, int x, int y) {
  211.   RECT src, dst;
  212.   src.left=0;
  213.   src.top=0;
  214.   src.bottom=getHeight();
  215.   src.right=getWidth();
  216.   dst.left=x;
  217.   dst.right=x+getWidth();
  218.   dst.top=y;
  219.   dst.bottom=y+getHeight();
  220.   blitToRect(canvas,&src,&dst,255);
  221. }
  222.  
  223. void SkinBitmap::blitRectToTile(CanvasBase *canvas, RECT *dest, RECT *src, int xoffs, int yoffs, int alpha) {
  224.   int startx,starty;
  225.  
  226.   int w,h;
  227.  
  228.   w = src->right-src->left;
  229.   h = src->bottom-src->top;
  230.  
  231.   RECT c;
  232.   if (GetClipBox(canvas->getHDC(), &c) == NULLREGION)
  233.         c = *dest;
  234.  
  235.     starty = c.top-((c.top - dest->top) % h)- yoffs;
  236.     startx = c.left-((c.left - dest->left) % w) - xoffs;
  237.  
  238.     for (int j=starty;j<c.bottom;j+=h)
  239.         for (int i=startx;i<c.right;i+=w) {
  240.       int xp=i;
  241.       int yp=j;
  242.       int xo=0;
  243.       int yo=0;
  244.       int _w=getWidth();
  245.       int _h=getHeight();
  246.       if (xp < c.left) {
  247.         xo=c.left-xp;
  248.         _w+=xo;
  249.         xp=c.left;
  250.       }
  251.       if (yp < c.top) {
  252.         yo=c.top-yp;
  253.         _h+=yo;
  254.         yp=c.top;
  255.       }
  256.       if (xp + _w >= c.right) _w=c.right-xp;
  257.       if (yp + _h >= c.bottom) _h=c.bottom-yp;
  258.       RECT _s={xo, yo, xo+_w, yo+_h};
  259.       RECT _d={xp, yp, xp+_w, yp+_h};
  260.       blitToRect(canvas, &_s, &_d, alpha);
  261.     }
  262.  
  263. }
  264.  
  265.  
  266. void SkinBitmap::blitTile(CanvasBase *canvas, RECT *dest, int xoffs, int yoffs, int alpha) {
  267.   RECT r={0,0,getWidth(),getHeight()};
  268.   blitRectToTile(canvas, dest, &r, xoffs, yoffs, alpha);
  269. }
  270.  
  271. #pragma warning(push) 
  272. #pragma warning(disable : 4799) 
  273.  
  274. void SkinBitmap::blitToRect(CanvasBase *canvas, RECT *src, RECT *dst, int alpha) { // only dst(top,left) are used
  275.   if (alpha <= 0) return;
  276.   if (alpha > 255) alpha = 255;
  277.  
  278.   HDC hdc = canvas->getHDC();
  279.   if (hdc == NULL) return;
  280.   void *dib=canvas->getBits();
  281.   HBITMAP hdib,hprevdibdcbm;
  282.   HDC hdibdc=NULL;
  283.   int cwidth,cheight;
  284.  
  285.   RECT destrect=*dst;
  286.   destrect.bottom=destrect.top+(src->bottom-src->top);
  287.   destrect.right=destrect.left+(src->right-src->left);
  288.  
  289.   RECT c;
  290.   int ctype=GetClipBox(hdc, &c);
  291.  
  292.   if (c.top > destrect.top) destrect.top=c.top;
  293.   if (c.left > destrect.left) destrect.left=c.left;
  294.   if (c.bottom < destrect.bottom) destrect.bottom=c.bottom;
  295.   if (c.right < destrect.right) destrect.right=c.right;
  296.  
  297. #ifdef NO_SIMPLEFASTMODE
  298.   dib=NULL;
  299. #endif
  300.  
  301.   if (destrect.right <= destrect.left || destrect.bottom <= destrect.top) return;
  302.   int xs,yp,xe,ye;
  303.  
  304.   if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
  305.   {
  306.     cwidth=destrect.right-destrect.left;
  307.     cheight=destrect.bottom-destrect.top;
  308.     BITMAPINFO bmidib={0,};
  309.     bmidib.bmiHeader.biSize=sizeof(bmidib.bmiHeader);
  310.     bmidib.bmiHeader.biWidth=cwidth;
  311.     bmidib.bmiHeader.biHeight=-cheight;
  312.     bmidib.bmiHeader.biPlanes=1;
  313.     bmidib.bmiHeader.biBitCount=32;
  314.     bmidib.bmiHeader.biCompression=BI_RGB;
  315.     hdib=CreateDIBSection(hdc,&bmidib,DIB_RGB_COLORS,&dib,NULL,0);
  316.     ASSERTPR(hdib != 0, "CreateDIBSection() failed #3");
  317.     hdibdc = CreateCompatibleDC(hdc);
  318.     hprevdibdcbm = (HBITMAP)SelectObject(hdibdc, hdib);
  319.     if (has_alpha || alpha < 255) BitBlt(hdibdc,0,0,cwidth,cheight,hdc,destrect.left,destrect.top,SRCCOPY);
  320.  
  321.     xs=0;
  322.     yp=0;
  323.     xe=cwidth;
  324.     ye=cheight;
  325.   }
  326.   else 
  327.   {
  328.     xs=destrect.left;
  329.     xe=destrect.right;
  330.     yp=destrect.top;
  331.     ye=destrect.bottom;
  332.  
  333.     cwidth/=4;
  334.   }
  335.   int xpo=(dst->left-destrect.left+xs)-(getX()+src->left);
  336.   int ypo=(dst->top-destrect.top+yp)-(getY()+src->top);
  337.  
  338.   if (yp < 0) yp=0;
  339.   if (xs < 0) xs=0;
  340.  
  341.   if (yp<getY()+ypo) yp=ypo+getY();
  342.   if (xs<getX()+xpo) xs=xpo+getX();
  343.  
  344.   if (xe > getWidth()+getX()+xpo) xe=getWidth()+getX()+xpo;
  345.   if (ye > getHeight()+getY()+ypo) ye=getHeight()+getY()+ypo;
  346.  
  347.   // blend bitmap to dib
  348.  
  349.   if (xs<xe) for (; yp < ye; yp ++) {
  350.     int xp=xe-xs;
  351.     unsigned int *dest=((unsigned int*)dib) + cwidth*yp + xs;
  352.     unsigned int *src=((unsigned int*)bits) + (yp-ypo)*fullimage_w + (xs-xpo);
  353.     
  354.     if (!has_alpha && alpha==255) // simple copy
  355.     {
  356.       MEMCPY(dest,src,xp*4);
  357.     }   
  358.     else if (!has_alpha) { // no alpha channel info, but just a simple blend
  359.       if (!HAS_MMX)
  360.         while (xp--) *dest++ = Blenders::BLEND_ADJ1(*src++, *dest, alpha);
  361.       #ifndef NO_MMX
  362.         else
  363.         {
  364.           if (xp>1) __asm
  365.           {
  366.             movd mm3, [alpha]
  367.             mov ecx, xp
  368.  
  369.             movq mm4, [SkinBitmap_mmx_revn2]
  370.             packuswb mm3, mm3 // 0000HHVV
  371.  
  372.             paddusw mm3, [SkinBitmap_mmx_one]
  373.             mov edi, dest
  374.  
  375.             punpcklwd mm3, mm3 // HHVVHHVV
  376.             mov esi, src
  377.         
  378.             punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
  379.             shr ecx, 1
  380.  
  381.             psubw mm4, mm3
  382.  
  383.             align 16
  384.             _blitAlpha_Loop1:
  385.   
  386.               movd mm0, [edi]
  387.  
  388.               movd mm1, [esi]
  389.               punpcklbw mm0, [SkinBitmap_mmx_zero]
  390.         
  391.               movd mm7, [edi+4]
  392.               punpcklbw mm1, [SkinBitmap_mmx_zero]
  393.  
  394.               pmullw mm0, mm4
  395.               pmullw mm1, mm3
  396.  
  397.               movd mm6, [esi+4]
  398.               punpcklbw mm7, [SkinBitmap_mmx_zero]
  399.             
  400.               punpcklbw mm6, [SkinBitmap_mmx_zero]
  401.  
  402.               pmullw mm7, mm4      
  403.               pmullw mm6, mm3
  404.  
  405.               paddw mm0, mm1
  406.  
  407.               psrlw mm0, 8
  408.  
  409.               packuswb mm0, mm0
  410.               add esi, 8   
  411.  
  412.               movd [edi], mm0
  413.               paddw mm7, mm6
  414.            
  415.               psrlw mm7, 8
  416.     
  417.               packuswb mm7, mm7
  418.  
  419.               movd [edi+4], mm7
  420.  
  421.               add edi, 8
  422.  
  423.             dec ecx
  424.             jnz _blitAlpha_Loop1
  425.             mov src, esi
  426.             mov dest, edi
  427.  
  428.           }
  429.           if (xp & 1) *dest++ = Blenders::BLEND_ADJ1_MMX(*src++, *dest, alpha);
  430.         } // mmx available
  431.       #endif // !NO_MMX
  432.     }
  433.     else if (alpha == 255) { // no global alpha, just alpha channel
  434.       if (!HAS_MMX)
  435.         while (xp--) *dest++ = Blenders::BLEND_ADJ2(*dest, *src++);
  436.       #ifndef NO_MMX
  437.         else
  438.         {
  439.           if (xp > 1) __asm
  440.           {
  441.             mov ecx, xp
  442.             shr ecx, 1
  443.             mov edi, dest
  444.             mov esi, src
  445.             align 16
  446.             _blitAlpha_Loop2:
  447.  
  448.             movd mm3, [esi]
  449.             movd mm5, [esi+4]
  450.  
  451.             movq mm2, [SkinBitmap_mmx_revn2]
  452.             psrld mm3, 24
  453.  
  454.             movq mm4, [SkinBitmap_mmx_revn2]
  455.             psrld mm5, 24
  456.           
  457.             movd mm0, [edi]
  458.             packuswb mm3, mm3 // 0000HHVV
  459.  
  460.             movd mm1, [esi]
  461.             packuswb mm5, mm5 // 0000HHVV
  462.           
  463.             movd mm6, [esi+4]
  464.             paddusw mm3, [SkinBitmap_mmx_one]
  465.  
  466.             punpcklwd mm3, mm3 // HHVVHHVV
  467.             paddusw mm5, [SkinBitmap_mmx_one]
  468.  
  469.             movd mm7, [edi+4]
  470.             punpcklwd mm5, mm5 // HHVVHHVV
  471.         
  472.             punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
  473.             punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
  474.  
  475.             punpcklbw mm6, [SkinBitmap_mmx_zero]
  476.             psubw mm4, mm5
  477.  
  478.             punpcklbw mm0, [SkinBitmap_mmx_zero]
  479.             psubw mm2, mm3
  480.  
  481.             punpcklbw mm7, [SkinBitmap_mmx_zero]
  482.             pmullw mm0, mm2
  483.           
  484.             pmullw mm7, mm4      
  485.             punpcklbw mm1, [SkinBitmap_mmx_zero]
  486.  
  487.             psubw mm2, mm3
  488.  
  489.             psrlw mm0, 8
  490.             psrlw mm7, 8
  491.             paddw mm0, mm1
  492.    
  493.             paddw mm7, mm6
  494.             packuswb mm0, mm0
  495.  
  496.             movd [edi], mm0
  497.             packuswb mm7, mm7
  498.                  
  499.             movd [edi+4], mm7
  500.  
  501.             add esi, 8
  502.             add edi, 8
  503.  
  504.             dec ecx
  505.             jnz _blitAlpha_Loop2
  506.             mov src, esi
  507.             mov dest, edi
  508.           }
  509.           if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, *src++);
  510.         } // HAS_MMX
  511.       #endif // ifndef NO_MMX
  512.     }
  513.     else { // both
  514.       if (!HAS_MMX)
  515.         while (xp--) *dest++ = Blenders::BLEND_ADJ3(*dest, *src++, alpha);
  516.       #ifndef NO_MMX
  517.         else
  518.         {
  519.           if (xp > 1) __asm
  520.           {
  521.             movd mm5, [alpha]
  522.             mov ecx, xp
  523.  
  524.             packuswb mm5, mm5 
  525.             shr ecx, 1
  526.  
  527.             paddusw mm5, [SkinBitmap_mmx_one]
  528.  
  529.             punpcklwd mm5, mm5        
  530.             mov edi, dest
  531.  
  532.             punpckldq mm5, mm5
  533.             mov esi, src
  534.  
  535.             align 16
  536.             _blitAlpha_Loop3:
  537.  
  538.             movd mm3, [esi] // VVVVVVVV
  539.             movd mm4, [esi+4] // VVVVVVVV
  540.  
  541.             movd mm0, [edi]    
  542.             psrld mm3, 24
  543.  
  544.             movd mm1, [esi]
  545.             psrld mm4, 24
  546.  
  547.             paddusw mm3, [SkinBitmap_mmx_one]
  548.             paddusw mm4, [SkinBitmap_mmx_one]
  549.  
  550.             movd mm7, [edi+4]    
  551.             punpcklwd mm3, mm3
  552.  
  553.             movd mm6, [esi+4]
  554.             punpcklwd mm4, mm4
  555.  
  556.             punpckldq mm3, mm3
  557.             punpckldq mm4, mm4
  558.           
  559.             pmullw mm3, mm5
  560.             pmullw mm4, mm5
  561.  
  562.             punpcklbw mm7, [SkinBitmap_mmx_zero]
  563.             punpcklbw mm6, [SkinBitmap_mmx_zero]
  564.  
  565.             movq mm2, [SkinBitmap_mmx_revn2]
  566.             psrlw mm3, 8
  567.  
  568.             psrlw mm4, 8  
  569.  
  570.             punpcklbw mm0, [SkinBitmap_mmx_zero]
  571.             punpcklbw mm1, [SkinBitmap_mmx_zero]
  572.  
  573.             psubw mm2, mm3
  574.             pmullw mm0, mm2      
  575.  
  576.             pmullw mm1, mm5
  577.             add esi, 8
  578.  
  579.             movq mm2, [SkinBitmap_mmx_revn2]
  580.             pmullw mm6, mm5
  581.     
  582.             paddusw mm0, mm1
  583.             psubw mm2, mm4
  584.  
  585.             pmullw mm7, mm2      
  586.             psrlw mm0, 8   
  587.  
  588.             packuswb mm0, mm0
  589.             paddusw mm7, mm6
  590.  
  591.             movd [edi], mm0
  592.             psrlw mm7, 8   
  593.                  
  594.             packuswb mm7, mm7
  595.  
  596.             movd [edi+4], mm7
  597.  
  598.             add edi, 8
  599.  
  600.             dec ecx
  601.             jnz _blitAlpha_Loop3
  602.             mov src, esi
  603.             mov dest, edi
  604.           }
  605.           if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, *src++, alpha);
  606.         } // HAS_MMX
  607.       #endif // ifndef NO_MMX
  608.     }
  609.   }
  610. #ifndef NO_MMX
  611.   Blenders::BLEND_MMX_END();
  612. #endif
  613.   // write bits back to dib.
  614.  
  615.   if (hdibdc) {
  616.     BitBlt(hdc,destrect.left,destrect.top,destrect.right-destrect.left,destrect.bottom-destrect.top,hdibdc,0,0,SRCCOPY);
  617.     SelectObject(hdibdc, hprevdibdcbm);
  618.     DeleteObject(hdib);
  619.     DeleteDC(hdibdc);
  620.   }
  621. }
  622.  
  623. #pragma warning(pop) 
  624.  
  625. void SkinBitmap::stretch(CanvasBase *canvas, int x, int y, int w, int h) {
  626.   RECT src, dst;
  627.   src.left=0;
  628.   src.top=0;
  629.   src.right=getWidth();
  630.   src.bottom=getHeight();
  631.   dst.left=x;
  632.   dst.right=x+w;
  633.   dst.top=y;
  634.   dst.bottom=y+h;
  635.   stretchToRectAlpha(canvas,&src,&dst,255);
  636. }
  637.  
  638. void SkinBitmap::stretchToRect(CanvasBase *canvas, RECT *r) {
  639.   stretch(canvas, r->left, r->top, r->right - r->left, r->bottom - r->top);
  640. }
  641.  
  642. void SkinBitmap::stretchRectToRect(CanvasBase *canvas, RECT *src, RECT *dst) {
  643.   stretchToRectAlpha(canvas,src,dst,255);
  644. }
  645.  
  646.  
  647. void SkinBitmap::stretchToRectAlpha(CanvasBase *canvas, RECT *r, int alpha) {
  648.   RECT re;
  649.   re.left=0; re.top=0;
  650.   re.right=getWidth(); re.bottom=getHeight();
  651.   stretchToRectAlpha(canvas,&re,r,alpha);
  652. }
  653.  
  654. void SkinBitmap::blitAlpha(CanvasBase *canvas, int x, int y, int alpha)
  655. {
  656.   RECT dst,src;
  657.   dst.left=x;
  658.   dst.top=y;
  659.   src.left=0;
  660.   src.top=0;
  661.   src.bottom=getHeight();
  662.   src.right=getWidth();
  663.   blitToRect(canvas,&src,&dst,alpha);
  664. }
  665. #pragma warning(push) 
  666. #pragma warning(disable : 4799) 
  667.  
  668. template <class C>
  669. class Stretcher {
  670. public:
  671.   static void _stretchToRectAlpha(SkinBitmap *bitmap, int ys, int ye, int xe, int xs, int xstart, int yv, void *dib, int cwidth, int dxv, int dyv, int alpha) {
  672.     int bitmap_x = bitmap->getX();
  673.     int bitmap_y = bitmap->getY();
  674.     int bmpheight = bitmap->getHeight();
  675.     int fullimage_w = bitmap->getFullWidth();
  676.     void *bits = bitmap->getBits();
  677.     int xp=xe-xs;
  678.     for (int yp = ys; yp < ye; yp ++) {
  679.       int t=yv>>16;
  680.       if (t < 0) t=0;
  681.       if (t >= bmpheight) t=bmpheight-1;
  682.       int *psrc=((int*)bits) + (t+bitmap_y)*fullimage_w + bitmap_x;
  683.       int *dest=((int*)dib) + cwidth*yp + xs;     
  684.  
  685.       C::stretch(xp, psrc, dest, xstart, dxv, alpha);
  686.  
  687.       yv+=dyv;
  688.     }
  689.   }
  690. };
  691.  
  692. // no alpha, just stretch
  693. class Stretch {
  694. public:
  695.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  696.     while (xp--) { //JFtodo: assembly optimize - these first two modes aren't used that much anyway
  697.       *dest++ = psrc[xv>>16];
  698.       xv+=dxv;
  699.     }
  700.   }
  701. };
  702.  
  703. // no alpha channel, just a global alpha val
  704. class StretchGlobal {
  705. public:
  706.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  707.     while (xp--) { //JFTODO: make MMX optimized version
  708.       *dest++ = Blenders::BLEND_ADJ1(psrc[xv>>16], *dest, alpha);
  709.       xv+=dxv;
  710.     }
  711.   }
  712. };
  713.  
  714. // alpha channel, no global alpha val
  715. class StretchChannel {
  716. public:
  717.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  718.     while (xp--) {
  719.       *dest++ = Blenders::BLEND_ADJ2(*dest, psrc[xv>>16]);
  720.       xv+=dxv;
  721.     }
  722.   }
  723. };
  724.  
  725. class StretchGlobalChannel {
  726. public:
  727.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  728.     while (xp--) {
  729.       *dest++ = Blenders::BLEND_ADJ3(*dest, psrc[xv>>16], alpha);
  730.       xv+=dxv;
  731.     }
  732.   }
  733. };
  734.  
  735.  
  736. #ifndef NO_MMX
  737.  
  738. // no alpha channel, just a global alpha val
  739. class StretchGlobalMMX {
  740. public:
  741.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  742.     while (xp--) { //JFTODO: make MMX optimized version
  743.       *dest++ = Blenders::BLEND_ADJ1_MMX(psrc[xv>>16], *dest, alpha);
  744.       xv+=dxv;
  745.     }
  746.   }
  747. };
  748.  
  749.  
  750. // alpha channel, no global alpha val
  751. class StretchChannelMMX {
  752. public:
  753.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  754.     if (xp>1) __asm
  755.     {
  756.       mov ecx, xp
  757.       mov edi, dest
  758.  
  759.       shr ecx, 1
  760.       mov esi, psrc
  761.  
  762.       mov edx, xv
  763.       mov ebx, dxv
  764.  
  765.       align 16
  766.     _stretchAlpha_Loop2:
  767.  
  768.       mov eax, edx
  769.       movd mm0, [edi]
  770.  
  771.       movq mm4, [SkinBitmap_mmx_revn2]
  772.       shr eax, 16
  773.  
  774.       movq mm2, [SkinBitmap_mmx_revn2]
  775.       punpcklbw mm0, [SkinBitmap_mmx_zero]
  776.  
  777.       movd mm3, [esi+eax*4]
  778.       movd mm1, [esi+eax*4]
  779.       
  780.       lea eax, [edx+ebx]
  781.       shr eax, 16
  782.  
  783.       movd mm7, [edi+4]
  784.       psrld mm3, 24
  785.  
  786.       packuswb mm3, mm3 // 0000HHVV
  787.       movd mm5, [esi+eax*4]
  788.  
  789.       movd mm6, [esi+eax*4]
  790.       psrld mm5, 24          
  791.  
  792.       paddusw mm3, [SkinBitmap_mmx_one]
  793.       punpcklbw mm6, [SkinBitmap_mmx_zero]
  794.  
  795.       packuswb mm5, mm5 // 0000HHVV
  796.       lea edx, [edx+ebx*2]
  797.         
  798.       paddusw mm5, [SkinBitmap_mmx_one]          
  799.       punpcklwd mm3, mm3 // HHVVHHVV
  800.  
  801.       punpcklwd mm5, mm5 // HHVVHHVV
  802.       add edi, 8
  803.       
  804.       punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
  805.  
  806.       punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
  807.  
  808.       psubw mm4, mm5
  809.  
  810.       psubw mm2, mm3
  811.  
  812.       punpcklbw mm7, [SkinBitmap_mmx_zero]
  813.       pmullw mm0, mm2
  814.         
  815.       pmullw mm7, mm4      
  816.       punpcklbw mm1, [SkinBitmap_mmx_zero]
  817.  
  818.       psubw mm2, mm3
  819.  
  820.       psrlw mm0, 8
  821.       psrlw mm7, 8
  822.       paddw mm0, mm1
  823.  
  824.       paddw mm7, mm6
  825.       packuswb mm0, mm0
  826.  
  827.       movd [edi-8], mm0
  828.       packuswb mm7, mm7
  829.                  
  830.       movd [edi-4], mm7
  831.  
  832.       dec ecx
  833.       jnz _stretchAlpha_Loop2
  834.       mov dest, edi
  835.       mov xv, edx
  836.     }
  837.  
  838.     if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, psrc[xv>>16]);
  839.   }
  840. };
  841.  
  842.  
  843. class StretchGlobalChannelMMX {
  844. public:
  845.   static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
  846.     if (xp>1) __asm
  847.     {
  848.       movd mm5, [alpha]
  849.       mov ecx, xp
  850.  
  851.       packuswb mm5, mm5 
  852.       shr ecx, 1
  853.  
  854.       paddusw mm5, [SkinBitmap_mmx_one]
  855.  
  856.       punpcklwd mm5, mm5        
  857.       mov edi, dest
  858.  
  859.       punpckldq mm5, mm5
  860.       mov esi, psrc
  861.  
  862.       mov edx, xv
  863.       mov ebx, dxv
  864.  
  865.       align 16
  866.     _stretchAlpha_Loop3:
  867.       movd mm0, [edi]    
  868.       mov eax, edx
  869.  
  870.       movd mm7, [edi+4]    
  871.       shr eax, 16
  872.  
  873.       movd mm1, [esi+eax*4]
  874.       movd mm3, [esi+eax*4] // VVVVVVVV
  875.  
  876.       lea eax, [edx+ebx]
  877.       psrld mm3, 24
  878.  
  879.       paddusw mm3, [SkinBitmap_mmx_one]
  880.  
  881.       punpcklwd mm3, mm3
  882.       shr eax, 16
  883.  
  884.       punpckldq mm3, mm3
  885.  
  886.       pmullw mm3, mm5
  887.  
  888.       movd mm4, [esi+eax*4] // VVVVVVVV
  889.       movd mm6, [esi+eax*4]
  890.  
  891.       movq mm2, [SkinBitmap_mmx_revn2]
  892.       psrld mm4, 24
  893.  
  894.       paddusw mm4, [SkinBitmap_mmx_one]
  895.       punpcklbw mm7, [SkinBitmap_mmx_zero]
  896.  
  897.       punpcklwd mm4, mm4
  898.       lea edx, [edx+ebx*2]
  899.  
  900.       punpckldq mm4, mm4
  901.       add edi, 8
  902.  
  903.       punpcklbw mm6, [SkinBitmap_mmx_zero]         
  904.       pmullw mm4, mm5
  905.  
  906.       psrlw mm3, 8
  907.  
  908.       punpcklbw mm0, [SkinBitmap_mmx_zero]
  909.  
  910.       punpcklbw mm1, [SkinBitmap_mmx_zero]
  911.       psubw mm2, mm3
  912.  
  913.       pmullw mm0, mm2      
  914.       pmullw mm1, mm5
  915.  
  916.       pmullw mm6, mm5
  917.       psrlw mm4, 8  
  918.  
  919.       movq mm2, [SkinBitmap_mmx_revn2]    
  920.       paddusw mm0, mm1
  921.       psubw mm2, mm4
  922.  
  923.       pmullw mm7, mm2      
  924.       psrlw mm0, 8   
  925.  
  926.       packuswb mm0, mm0
  927.       paddusw mm7, mm6
  928.  
  929.       movd [edi-8], mm0
  930.       psrlw mm7, 8   
  931.              
  932.       packuswb mm7, mm7
  933.  
  934.       movd [edi-4], mm7
  935.  
  936.       dec ecx
  937.       jnz _stretchAlpha_Loop3
  938.       mov xv, edx
  939.       mov dest, edi
  940.     }
  941.  
  942.     if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, psrc[xv>>16], alpha);
  943.   }
  944. };
  945. #endif
  946.  
  947.  
  948. class __Stretch : public Stretcher<Stretch> {};
  949. class __StretchGlobal : public Stretcher<StretchGlobal> {};
  950. class __StretchChannel : public Stretcher<StretchChannel> {};
  951. class __StretchGlobalChannel : public Stretcher<StretchGlobalChannel> {};
  952.  
  953. #ifndef NO_MMX
  954. class __StretchGlobalMMX : public Stretcher<StretchGlobalMMX> {};
  955. class __StretchChannelMMX : public Stretcher<StretchChannelMMX> {};
  956. class __StretchGlobalChannelMMX : public Stretcher<StretchGlobalChannelMMX> {};
  957. #endif
  958.  
  959. #pragma warning(pop) 
  960.  
  961.  
  962. void SkinBitmap::stretchToRectAlpha(CanvasBase *canvas, RECT *_src, RECT *_dst, int alpha)
  963. {
  964.   if (alpha <= 0) return;
  965.   if (alpha > 255) alpha = 255;
  966.  
  967.   RECT src=*_src;
  968.   RECT dst=*_dst;
  969.  
  970.   if ((src.right-src.left) == (dst.right-dst.left) &&
  971.       (src.bottom-src.top) == (dst.bottom-dst.top))
  972.   {
  973.     blitToRect(canvas,_src,_dst,alpha);
  974.     return;
  975.   }
  976.  
  977.   //FG> this is a hack, we should support subpixels instead
  978.   if (src.left == src.right) {
  979.     if (src.right < getWidth()) 
  980.       src.right++;
  981.     else
  982.       src.left--;
  983.   } 
  984.   if (src.top== src.bottom) {
  985.     if (src.bottom < getHeight()) 
  986.       src.bottom++;
  987.     else
  988.       src.top--;
  989.   } 
  990.  
  991.   if (src.left >= src.right || src.top >= src.bottom) return;
  992.   if (dst.left >= dst.right || dst.top >= dst.bottom) return;
  993.  
  994.   void *dib=canvas->getBits();
  995.   HDC hdc=canvas->getHDC();
  996.   HBITMAP hdib,hprevdibdcbm;
  997.   HDC hdibdc=NULL;
  998.   int cwidth, cheight;
  999.  
  1000.   int dyv=((src.bottom-src.top)<<16)/(dst.bottom-dst.top);
  1001.   int dxv=((src.right-src.left)<<16)/(dst.right-dst.left);  
  1002.   int yv=(src.top<<16);
  1003.   int xstart=(src.left<<16);
  1004.  
  1005.   RECT c;
  1006.   int ctype=GetClipBox(hdc, &c);
  1007.   if (c.top > dst.top) 
  1008.   {
  1009.     yv+=(c.top-dst.top)*dyv;
  1010.     dst.top=c.top;
  1011.   }
  1012.   if (c.left > dst.left)
  1013.   {
  1014.     xstart+=(c.left-dst.left)*dxv;
  1015.     dst.left=c.left;
  1016.   }
  1017.   if (c.bottom < dst.bottom) dst.bottom=c.bottom;
  1018.   if (c.right < dst.right) dst.right=c.right;
  1019.  
  1020.   if (dst.right <= dst.left || dst.bottom <= dst.top) return;
  1021.  
  1022.   int xs,xe,ys,ye;
  1023.  
  1024. #ifdef NO_SIMPLEFASTMODE
  1025.   dib=NULL;
  1026. #endif
  1027.   if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
  1028.   {
  1029.     // create dib
  1030.     BITMAPINFO bmidib={0,};
  1031.     bmidib.bmiHeader.biSize=sizeof(bmidib.bmiHeader);
  1032.     bmidib.bmiHeader.biWidth=dst.right-dst.left;
  1033.     bmidib.bmiHeader.biHeight=dst.top-dst.bottom; // this should be negative
  1034.     bmidib.bmiHeader.biPlanes=1;
  1035.     bmidib.bmiHeader.biBitCount=32;
  1036.     bmidib.bmiHeader.biCompression=BI_RGB;
  1037.     hdib=CreateDIBSection(hdc,&bmidib,DIB_RGB_COLORS,&dib,NULL,0);
  1038.     ASSERTPR(hdib != 0, "CreateDIBSection() failed #5");
  1039.     hdibdc = CreateCompatibleDC(hdc);
  1040.     hprevdibdcbm = (HBITMAP)SelectObject(hdibdc, hdib);
  1041.     if (has_alpha || alpha < 255) BitBlt(hdibdc,0,0,dst.right-dst.left,dst.bottom-dst.top,hdc,dst.left,dst.top,SRCCOPY);
  1042.     cwidth=dst.right-dst.left;
  1043.     cheight=dst.bottom-dst.top;
  1044.     xs=0;
  1045.     ys=0;
  1046.     xe=dst.right-dst.left;
  1047.     ye=dst.bottom-dst.top;
  1048.   }
  1049.   else 
  1050.   {
  1051.     xs=dst.left;
  1052.     xe=dst.right;
  1053.     ys=dst.top;
  1054.     ye=dst.bottom;
  1055.     cwidth/=4;
  1056.   }
  1057.  
  1058.   // stretch and blend bitmap to dib
  1059.  
  1060.   if (xstart < 0) xstart=0;
  1061.  
  1062.   if (xs<xe) {
  1063.     if (!has_alpha) {    // doesn't have alpha channel
  1064.       if (alpha == 255) {    // no global alpha
  1065.         __Stretch::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1066.       } else {    // has global alpha
  1067. #ifndef NO_MMX
  1068.         if (HAS_MMX) {
  1069.           __StretchGlobalMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1070.         } else
  1071. #endif
  1072.         {
  1073.           __StretchGlobal::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1074.         }
  1075.       }
  1076.     } else {    // has alpha channel
  1077.       // FUCKO: JF> BRENNAN FIX THESE BITCHES :)
  1078.       if (alpha == 255) {    // no global alpha
  1079. #ifndef NO_MMX
  1080.         if (HAS_MMX) {
  1081.           __StretchChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1082.         } else 
  1083. #endif
  1084.         {
  1085.           __StretchChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1086.         }
  1087.       } else {    // has global alpha
  1088. #ifndef NO_MMX
  1089.         if (HAS_MMX) {
  1090.           __StretchGlobalChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1091.         } else 
  1092. #endif
  1093.         {
  1094.           __StretchGlobalChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, cwidth, dxv, dyv, alpha);
  1095.         }
  1096.       }
  1097.     }
  1098.   }
  1099.  
  1100. #ifndef NO_MMX
  1101.   Blenders::BLEND_MMX_END();
  1102. #endif
  1103.   // write bits back to dib.
  1104.  
  1105.   if (hdibdc) {
  1106.     BitBlt(hdc,dst.left,dst.top,dst.right-dst.left,dst.bottom-dst.top,hdibdc,0,0,SRCCOPY);
  1107.     SelectObject(hdibdc, hprevdibdcbm);
  1108.     DeleteObject(hdib);
  1109.     DeleteDC(hdibdc);
  1110.   }
  1111. }
  1112.  
  1113. COLORREF SkinBitmap::getPixel(int x, int y) {
  1114.   ASSERT(bits != NULL);
  1115.   if (x < 0 || y < 0 || x >= getFullWidth()-getX() || y>= getFullHeight()-getY()) return (COLORREF)0;
  1116.   return (COLORREF)(((int*)bits)[x+getX()+(y+getY())*getFullWidth()]);
  1117. }
  1118.  
  1119. void *SkinBitmap::getBits() {
  1120.   return bits;
  1121. }
  1122.